﻿
Imports System.Text

Public Module _rnd
#If VBRND Then
#If NEWRANDOM Then
    Public Function rnd() As Double
        Static seed As Double = CType(Now.Millisecond, Double) / Now.Ticks
        Static rndtimes As UInt64 = 1
        seed = (seed * rndtimes + Now.Millisecond()) / Now.Ticks
        rndtimes += 1

        Return seed
    End Function
#Else
    Public Function rnd() As Double
        Return Microsoft.VisualBasic.VBMath.Rnd()
    End Function

#If RETIRED Then
    Public Function rnd() As Double
        Dim rtn As Double
        rtn = Microsoft.VisualBasic.VBMath.Rnd()
        rtn *= ((Now.Ticks() Mod 100) \ 10) + 1
        rtn -= Int(rtn)
#If RETIRED Then
        Try
            rtn -= Convert.ToInt32(rtn)
        Catch ex As Exception
            raiseError("cannot convert rtn to int32, rtn " + Convert.ToString(rtn) + _
                       ", fallback to Microsoft.VisualBasic.VBMath.Rnd()", errorHandle.errorType.warning)
            rtn = Microsoft.VisualBasic.VBMath.Rnd()
        End Try
#End If

        Return rtn
    End Function
#End If
#End If

#If Not NEWRANDOM Then
#If PocketPC OrElse Smartphone Then
    Private Class rndtimes
        Public Shared d As UInt64
    End Class
#ElseIf TIMESBASED_RANDOMIZE Then
    Private Class rndtimes
        <ThreadStatic()> Public Shared d As UInt64
    End Class
#End If
#End If

#If Not TIMESBASED_RANDOMIZE AndAlso Not NEWRANDOM Then
    Sub New()
        Microsoft.VisualBasic.VBMath.Randomize(Now.hires_ticks())
    End Sub
#End If

    Public Function rnd(ByVal min As Double, ByVal max As Double, Optional ByVal int As Boolean = False, _
                        Optional ByVal forceRandomize As Boolean = False) As Double
        Dim result As Double
#If TIMESBASED_RANDOMIZE Then
        If rndtimes.d >= 1000 OrElse rndtimes.d = 0 OrElse forceRandomize Then
            rndtimes.d = 1
            Microsoft.VisualBasic.VBMath.Randomize()
        Else
            rndtimes.d += 1
        End If
#End If

        If min > max Then
            swap(min, max)
        End If
        result = rnd() * (max - min) + min

        If int Then
            Return Math.Truncate(result)
        Else
            Return result
        End If
    End Function
#Else
    <ThreadStatic()> Private _r As Random

    Private Function i(ByVal d As Int64) As Int32
        If d > maxInt32 Then
            Return maxInt32
        ElseIf d < minInt32 Then
            Return minInt32
        Else
            Return d
        End If
    End Function

    Private Function i(ByVal d As Double) As Int32
        If d > maxInt32 Then
            Return maxInt32
        ElseIf d < minInt32 Then
            Return minInt32
        Else
            Return d
        End If
    End Function

    Public Function r() As Random
        If _r Is Nothing Then
            _r = New Random()
        End If
        Return _r
    End Function

    Private Function ri(ByVal r As Random, ByVal min As Int32, ByVal max As Int32) As Int32
        assert(Not r Is Nothing)
        Return r.Next(min, max)
    End Function

    Private Function ri(ByVal min As Int32, ByVal max As Int32) As Int32
        Return ri(r(), min, max)
    End Function

    Public Function rnd_int(ByVal r As Random, ByVal min As Int32, ByVal max As Int32) As Int32
        Return ri(r, min, max)
    End Function

    Public Function rnd_int(ByVal min As Int32, ByVal max As Int32) As Int32
        Return ri(min, max)
    End Function

    Public Function rnd_uint(ByVal min As UInt32, ByVal max As UInt32) As UInt32
        Return next_double() * (max - min) + min
    End Function

    Public Function next_double(ByVal r As Random) As Double
        assert(Not r Is Nothing)
        Return r.NextDouble()
    End Function

    Public Function next_double() As Double
        Return next_double(r())
    End Function

    Public Function next_bytes(ByVal r As Random, ByVal buff() As Byte) As Boolean
        assert(Not r Is Nothing)
        If buff Is Nothing Then
            Return False
        Else
            r.NextBytes(buff)
            Return True
        End If
    End Function

    Public Function next_bytes(ByVal buff() As Byte) As Boolean
        Return next_bytes(r(), buff)
    End Function

    Public Function next_bytes(ByVal r As Random, ByVal buff As bytes) As Boolean
        Return next_bytes(r, +buff)
    End Function

    Public Function next_bytes(ByVal buff As bytes) As Boolean
        Return next_bytes(r(), buff)
    End Function

    Private Function rd(ByVal min As Double, ByVal max As Double) As Double
        Dim rtn As Double = 0
        rtn = next_double()
        Dim len As Double = 0
        len = max - min
        If len <> 1 Then
            rtn *= len
        End If
        rtn += min
        Return rtn
    End Function

    Public Function rnd_double(ByVal min As Double, ByVal max As Double) As Double
        Return rd(min, max)
    End Function

    Public Function rnd(ByVal min As Int32, ByVal max As Int32, ByVal int As Boolean) As Double
        If int Then
            Return ri(min, max)
        Else
            Return rd(min, max)
        End If
    End Function

    Public Function rnd(ByVal min As Int64, ByVal max As Int64, ByVal int As Boolean) As Double
        If int Then
            Return ri(i(min), i(max))
        Else
            Return rd(min, max)
        End If
    End Function

    Public Function rnd(ByVal min As Int32, ByVal max As Int64, ByVal int As Boolean) As Double
        If int Then
            Return ri(min, i(max))
        Else
            Return rd(min, max)
        End If
    End Function

    Public Function rnd(ByVal min As Int64, ByVal max As Int32, ByVal int As Boolean) As Double
        If int Then
            Return ri(i(min), max)
        Else
            Return rd(min, max)
        End If
    End Function

    Public Function rnd(ByVal min As Double, ByVal max As Double) As Double
        Return rd(min, max)
    End Function

    Public Function rnd(ByVal min As Double, ByVal max As Double, ByVal int As Boolean) As Double
        If int Then
            Return ri(i(min), i(max))
        Else
            Return rd(min, max)
        End If
    End Function
#End If

    Public Function rndenchars(ByVal r As Random,
                               ByVal length As Int64,
                               Optional ByVal careCase As Boolean = True) As String
        Dim rtn As StringBuilder = Nothing
        rtn = New StringBuilder()
        For i As Int64 = 0 To length - 1
            rtn.Append(rndenchar(r, careCase))
        Next

        Return Convert.ToString(rtn)
    End Function

    Public Function rndenchars(ByVal length As Int64, Optional ByVal careCase As Boolean = True) As String
        Return rndenchars(r(), length, careCase)
    End Function

    Private ReadOnly a As Int32 = Convert.ToInt32(character.a)
    Private ReadOnly z As Int32 = Convert.ToInt32(character.z)
    Private ReadOnly z_p_1 As Int32 = z + 1
    Private ReadOnly _A As Int32 = Convert.ToInt32(character._A)
    Private ReadOnly a_A_diff As Int32 = _A - a

    Public Function rndenchar(ByVal r As Random, Optional ByVal careCase As Boolean = True) As Char
        Return Convert.ToChar(ri(r, a, z_p_1) + ifoper(careCase AndAlso ri(r, 0, 2) = 0, a_A_diff, 0))
    End Function

    Public Function rndenchar(Optional ByVal careCase As Boolean = True) As Char
        Return rndenchar(r(), careCase)
    End Function

    Public Function rndbyte() As Byte
        Return rnd(0, maxInt8 + 1, True)
    End Function

    Public Function rndbytes(Optional ByVal size As UInt64 = 1024) As bytes
        Dim rtn As bytes = Nothing
        rtn = New bytes()
        rtn.size() = size
        For i As UInt64 = 0 To size - 1
            rtn(i) = rndbyte()
        Next
        Return rtn
    End Function

    Public Function rndalpha() As Byte
        Return rnd(192, maxUInt8 + 1, True)
    End Function

    Public Function rndcolor() As Drawing.Color
#If PocketPC OrElse Smartphone Then
        Return Drawing.Color.FromArgb(rndbyte(), rndbyte(), rndbyte())
#Else
        Return Drawing.Color.FromArgb(rndalpha(), rndbyte(), rndbyte(), rndbyte())
#End If
    End Function
End Module
